<?php


namespace App\Service\BankPay;

use App\Model\Dao\BankInfoDao;
use App\Model\Dao\ChannelInfoDao;
use App\Model\Enum\BankTypeEnum;
use App\Service\Bank\BankInnerService;
use App\Service\Bank\BankTestService;
use App\Service\Bank\IBankInterface;
use App\Utils\CustomUtils;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Arr;

/**
 * Class BankPayService
 * 银行支付业务处理
 *
 * @package App\Service\BankPay
 * @method doPay(array $params) 支付
 * @method doRefund(array $params) 退款
 * @method doTransfer(array $params) 转帐
 * @method doOrderQuery(array $params) 支付查询
 * @method doRefundQuery(array $params) 退款查询
 * @method doTransferQuery(array $params) 转账查询
 */
class BankPayService {

    /**
     * 银行类型到业务代码实现的映射
     */
    const SERVICE_MAP = [
        BankTypeEnum::TEST => BankTestService::class,
    ];

    const MAGIC_FUNC = [
        'doPay',
        'doRefund',
        'doTransfer',
        'doOrderQuery',
        'doRefundQuery',
        'doTransferQuery',
    ];

    /**
     * @var ChannelInfoDao
     * @Inject()
     */
    private $ChannelInfoDao;

    /**
     * @var BankInfoDao
     * @Inject()
     */
    private $BankInfoDao;

    /**
     * @param $name
     * @param $arguments
     *
     * @return mixed
     * @throws \Exception
     */
    public function __call ($name, $arguments) {

        if (!in_array($name, self::MAGIC_FUNC)) {
            throw new \Exception(trans('bank.not_support.function', ['function' => $name]));
        }

        $params = $arguments[0];

        $channelNo = Arr::pull($params, 'channelNo');

        $channel = $this->ChannelInfoDao->getWhere(['channelNo' => $channelNo, 'status' => 1]);

        if (!$channel) {
            throw new \Exception(trans('bank.channel.not_found', ['channel_no' => $channelNo]));
        }

        // 接口功能检测
        switch ($name) {
            case 'doPay':
            case 'doOrderQuery':
                if (!$channel['canPay'])
                    throw new \Exception(trans('bank.channel.not_support.pay', ['channel_no' => $channelNo]));
                break;
            case 'doRefund':
            case 'doRefundQuery':
                if (!$channel['canRefund'])
                    throw new \Exception(trans('bank.channel.not_support.refund', ['channel_no' => $channelNo]));
                break;
            case 'doTransfer':
            case 'doTransferQuery':
                if (!$channel['canTransfer'])
                    throw new \Exception(trans('bank.channel.not_support.transfer', ['channel_no' => $channelNo]));
                break;
        }

        $bankId = $channel['bankId'];

        $bank = $this->BankInfoDao->getWhere(['id' => $bankId, 'status' => 1]);

        if (!$bank) {
            throw new \Exception(trans('bank.not_found'));
        }

        $bankType = $bank['type'];

        // 执行业务代码
        return $this->_getBankService($bankType)->$name($params, $channel, $bank);
    }

    /**
     * @param string $bankType 银行类型
     *
     * @return mixed|IBankInterface
     * @throws \Exception
     */
    protected function _getBankService ($bankType) {

        // 检查是否有效
        if (!Arr::exists(self::SERVICE_MAP, $bankType)) {
            throw new \Exception(trans('bank.not_support.type', ['type' => $bankType]));
        }

        return ApplicationContext::getContainer()->get(self::SERVICE_MAP[$bankType]);
    }
}
